#include "ad9910_ctrl.h"
#include <QMessageBox>
#include <QTimer>
#include <QThread>

AD9910_CTRL::AD9910_CTRL(QObject *parent) : QObject(parent)
{
    this->tcpClient = new QTcpSocket(this);
}

QByteArray AD9910_CTRL::genByteArr_Profile(const uint16_t addrStepRate, RAM_MODE mode)
{
    QByteArray byteArr;
    byteArr.append(static_cast<char>(TCP_FRAME_HEAD::Single));
    byteArr.append(static_cast<char>(CMD_HEAD::SetProfile));

    byteArr.append(static_cast<char>((addrStepRate >> 8) & 0xFF)); // 地址步进率高8位
    byteArr.append(static_cast<char>(addrStepRate & 0xFF));        // 地址步进率低8位

    static constexpr uint16_t endAddr = 1023;
    static constexpr uint16_t startAddr = 0;

    byteArr.append(static_cast<char>((endAddr >> 8) & 0xFF));   // 结束地址高8位
    byteArr.append(static_cast<char>(endAddr & 0xFF));          // 结束地址低8位
    byteArr.append(static_cast<char>((startAddr >> 8) & 0xFF)); // 起始地址高8位
    byteArr.append(static_cast<char>(startAddr & 0xFF));        // 起始地址低8位

    byteArr.append(static_cast<char>(mode));

    return byteArr;
}

QByteArray AD9910_CTRL::genByteArr_Update()
{
    QByteArray byteArr;
    byteArr.append(static_cast<char>(TCP_FRAME_HEAD::Single));
    byteArr.append(static_cast<char>(CMD_HEAD::SetUpdate));
    return byteArr;
}

/**
 * @brief 生成设置定时器的字节数组
 *
 * 根据传入的参数生成设置定时器的字节数组。
 *
 * @param enable 是否启用定时器
 * @param sec 秒
 * @param usec 微秒
 *
 * @return QByteArray 生成的字节数组
 */
QByteArray AD9910_CTRL::genByteArr_SetTimer(bool enable, const uint32_t sec, const uint32_t usec)
{
    QByteArray byteArr;
    byteArr.append(static_cast<char>(TCP_FRAME_HEAD::Single));
    byteArr.append(static_cast<char>(CMD_HEAD::SetTimer));

    if (!enable)
    {
        byteArr.append(static_cast<char>(0x00)); // 禁用定时器
        return byteArr;
    }
    byteArr.append(static_cast<char>(0x01)); // 启用定时器

    byteArr.append(static_cast<char>((sec >> 8) & 0xFF));  // 高8位
    byteArr.append(static_cast<char>(sec & 0xFF));         // 低8位
    byteArr.append(static_cast<char>((usec >> 8) & 0xFF)); // 高8位
    byteArr.append(static_cast<char>(usec & 0xFF));        // 低8位
    return byteArr;
}

QVector<uint16_t> AD9910_CTRL::genRamData(const QMap<int, int> points)
{
    QVector<uint16_t> ramData(1024, 0x0000);

    //* interpolation from first point
    if (!points.contains(0))
    {
        for (int i = 0; i < points.firstKey(); i++)
        {
            ramData[i] = (uint16_t)(points.first() / points.firstKey() * i); // y = y_0 / x_0 * i
        }
    }

    for (auto it = points.cbegin(); it != points.cend(); ++it)
    {
        //* interpolation between two points
        if (it + 1 != points.cend())
        {
            for (int i = it.key(); i < (it + 1).key(); i++)
            {
                ramData[i] = (uint16_t)((it.value() - (it + 1).value()) / (it.key() - (it + 1).key()) * (i - it.key()) + it.value()); // y = (y_0 - y_1) / (x_0 - x_1) * (i - x_0) + y_0
            }
        }
        else if (!points.contains(1023))
        {
            //* interpolation to last point
            for (int i = it.key(); i <= 1023; i++)
            {
                ramData[i] = (uint16_t)((0 - points.last()) / (1023 - points.lastKey()) * (i - 1023) + 0); // y = (0 - y_n) / (1023-x_n) * (i - x_n) + y_n
            }
        }
    }

    return ramData;
}

/**
 * @brief 发送单个数据包
 *
 * 通过TCP客户端发送单个数据包到ARM。
 *
 * @param data 要发送的数据包
 * @return 如果发送成功返回true，否则返回false
 */
bool AD9910_CTRL::sendSingleData(const QByteArray &data)
{
    if (this->tcpClient->state() != QAbstractSocket::ConnectedState)
    {
        return false;
    }
    this->tcpClient->write(data);

    if (this->tcpClient->waitForBytesWritten() == false)
    {
        return false;
    }
    return true;
}

bool AD9910_CTRL::sendRamData(const QVector<uint16_t> &data)
{
    if (data.size() != 1024)
    {
        return false;
    }
    if (this->tcpClient->state() != QAbstractSocket::ConnectedState)
    {
        return false;
    }

    QVector<uint16_t> dataRev(1024, 0);
    for (int i = 0; i < 1024; i++)
    {
        dataRev[i] = data[1023 - i]; // 将数据反转，因为AD9910的RAM是从高地址向低地址写入数据的
    }

    QByteArray byteArr;

    for (int i = 0; i < 32; i++)
    {
        if (i == 0)
        {
            //* 数据包头部
            byteArr.append(static_cast<char>(TCP_FRAME_HEAD::First));
            byteArr.append(static_cast<char>(CMD_HEAD::SetRamData));
        }
        else if (i == 31)
        {
            //* 数据包尾部
            byteArr.append(static_cast<char>(TCP_FRAME_HEAD::Last));
        }
        else
        {
            //* 数据包中间部分
            byteArr.append(static_cast<char>(TCP_FRAME_HEAD::Middle));
        }

        for (int j = 32 * i; j < 32 * (i + 1); j++)
        {
            byteArr.append(static_cast<char>((dataRev[j] >> 8) & 0xFF)); // 高8位
            byteArr.append(static_cast<char>(dataRev[j] & 0xFF));        // 低8位
        }
        this->tcpClient->write(byteArr);
        QThread::msleep(20); // 阻塞延时20ms
        if (this->tcpClient->waitForBytesWritten() == false)
        {
            return false;
        }
        else
        {
            byteArr.clear(); // 清空数据包，准备下一次发送
        }
    }
    return true;
}
